﻿using System;
using nRoute.Components.Composition;
using nRoute.Utilities;

namespace nRoute.Components.Composition
{
    public class FactoryResourceLocator<T>
        : ResourceLocatorBase
		where
			T : class
	{
        private readonly Object _lock = new Object();
        private ILifetimeManager _lifetimeManager;
		private Func<ITypeBuilder, T> _factory;

        public FactoryResourceLocator(Func<ITypeBuilder, T> factory)
			: this(factory, null) { }

		public FactoryResourceLocator(Func<ITypeBuilder, T> factory, ILifetimeManager lifetimeManager)
		{
            Guard.ArgumentNotNull(factory, "factory");

            _lifetimeManager = lifetimeManager ?? new PerInstanceLifetimeManager();
            _factory = factory;
		}

#region Overrides

        protected override Object GetInstance(ITypeBuilder typeBuilder)
        {
            if (_lifetimeManager != null)
            {
                lock (_lock)
                {
                    if (_lifetimeManager != null && !this.IsDisposed)
                    {
                        return (T)_lifetimeManager.ManageBuild(typeBuilder, CreateResourceImplementationInstance);
                    }
                }
            }
            return null;
        }

        protected override void Dispose(bool disposing)
        {
            if (disposing)
            {
                if (_lifetimeManager != null)
                {
                    lock (_lock)
                    {
                        if (_lifetimeManager != null) 
                        {
                            _lifetimeManager.Dispose();
                            _lifetimeManager = null;
                        }
                        _factory = null;
                    }
                }
            }
        }

#endregion 

#region Helpers

        protected virtual Object CreateResourceImplementationInstance(ITypeBuilder typeBuilder)
		{
			return _factory(typeBuilder);			
		}
		
#endregion

        ~FactoryResourceLocator() { Dispose(false); }

	}
}